package com.lhczf.lucenedb.production;

import com.lhczf.lucenedb.bean.DataWrap;
import com.lhczf.lucenedb.consumer.WrapThreadFactory;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;

/**
 * @author: 刘华春
 * @date: 2019/2/6
 */
@Slf4j
public abstract class AbstractDataProduction<T> extends AbstractDataQueues implements Runnable {

    @Getter
    private WrapUncaughtExceptionHandler warpExceptionHandler = new WrapUncaughtExceptionHandler();
    DataWrap<T> data;

    AbstractDataProduction() {
        createDataWrap();
    }

    /**
     * 创建一个当前类的一个对象
     *
     * @return com.lhczf.lucenedb.production.AbstractDataProduction
     */
    abstract AbstractDataProduction<T> createDataProduction();

    /**
     * 设置待解析数据的数据类型
     *
     * @return 数据类型名称
     */
    abstract String configDataType();

    /**
     * 设置解析当前索引的配置文件的文件名称，此文件保存在classpath路径中的mapping目录下
     *
     * @return 解析文件名字
     */
    abstract String configAnalysisFileName();

    /**
     * 设置当前线程处理的那个索引
     *
     * @return 索引名字
     */
    public abstract String configIndexName();

    /**
     * 当线程运行过程中出现未捕获异常时，当前线程是否自我修复，自动启动一个线程
     *
     * @return true 表示启动自我修复， false 关闭此功能
     */
    public abstract boolean autoRecover();

    /**
     * 运行时的线程数配置
     *
     * @return 当前线程运行时的线程数
     */
    public abstract int runtimeThreadNum();

    @Override
    protected void dataQueueConfig() {
        log.info("the methond is empty");
    }

    void publishData() {
        BlockingQueue blockingQueue = DATA_QUEUE.computeIfAbsent(configIndexName(), k -> new LinkedBlockingQueue());
        try {
            blockingQueue.put(data);
            createDataWrap();
            return;
        } catch (InterruptedException e) {
            log.error("", e);
            Thread.currentThread().interrupt();
        }
        createDataWrap();
    }

    private void createDataWrap() {
        data = new DataWrap<>();
        data.setType(configDataType());
        data.setConfig(configAnalysisFileName());
    }

    public class WrapUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            log.error("线程在运行过程中产生了未捕获的异常。 ", e);
            if (autoRecover()) {
                AbstractDataProduction<T> dataProduction = createDataProduction();
                ThreadFactory factory = new WrapThreadFactory(t.getName());
                factory.newThread(dataProduction).start();
            } else {
                log.info("当前线程的自我修复开关为：{}", autoRecover());
            }
        }
    }
}
